// Copyright (c) 2024, the Dart project authors.
// All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:ffi' as ffi;

import 'package:meta/meta.dart' show internal;

import 'napi.dart';
import 'arkreference.dart';
import 'types.dart';

void _check(napi_value exception) {
  if (exception != ffi.Pointer.fromAddress(0)) {
    Napi.throwException(exception);
  }
}

@internal
extension NapiResultMethods on NapiResult {
  void check() => _check(exception);

  int get byte {
    check();
    return b;
  }

  int get short {
    check();
    return s;
  }

  int get char {
    check();
    return c;
  }

  int get integer {
    check();
    return i;
  }

  int get long {
    check();
    return l;
  }

  double get float {
    check();
    return f;
  }

  double get doubleFloat {
    check();
    return d;
  }

  NapiObjectPtr get objectPointer {
    check();
    return value;
  }

  NapiObjectRefType get referenceType {
    check();
    return NapiObjectRefType(i);
  }

  ArkReference get reference {
    final pointer = objectPointer;
    return pointer == ffi.Pointer.fromAddress(0) ? arkNullReference : ArkGlobalReference(ffi.Pointer.fromAddress(pointer.address));
  }

  T object<T extends ArkObject?>(T Function(ArkReference) fromReference) {
    return fromReference(reference);
  }

  bool get boolean {
    check();
    return z;
  }
}

@internal
extension NapiIdLookupResultMethods on NapiPointerResult<ffi.Void> {
  NapiMethodIDPtr get methodID {
    if (isError) {
      throw Exception('Method ID lookup failed');
    }
    return pointer!.cast<ffi.Void>();
  }

  NapiFieldIDPtr get fieldID {
    if (isError) {
      throw Exception('Field ID lookup failed');
    }
    return pointer!.cast<ffi.Void>();
  }

  ffi.Pointer<ffi.Void> get checkedRef {
    if (isError) {
      throw Exception('Reference lookup failed');
    }
    return pointer!;
  }

  ffi.Pointer<T> getPointer<T extends ffi.NativeType>() {
    if (isError) {
      throw Exception('Pointer lookup failed');
    }
    return pointer!.cast<T>();
  }
}

@internal
extension NapiClassLookupResultMethods on NapiClassLookupResult {
  NapiClassPtr get checkedClassRef {
    if (isError) {
      throw Exception('Class lookup failed');
    }
    return ffi.Pointer.fromAddress(value);
  }
}

@internal
extension NapiThrowableCheckMethod on NapiThrowablePtr {
  void check() {
    _check(this);
  }
}



